package com.casic.ops.runner.pipeline.node;

import com.casic.ops.entity.domain.MachineInfoDO;
import com.casic.ops.entity.dto.pipeline.datastructure.Logger.NodeLogger;
import com.casic.ops.entity.dto.pipeline.datastructure.constant.CommandConst;
import com.casic.ops.entity.dto.pipeline.datastructure.executecontext.PipelineExecuteContext;
import com.casic.ops.handler.pipeline.PipelineExecuteLoggerSocketService;
import com.casic.ops.runner.pipeline.manager.ChannelManager;
import com.casic.ops.runner.ssh.SshClient;
import com.casic.ops.runner.ssh.SshClientFactory;
import com.casic.ops.service.api.MachineInfoService;
import com.casic.ops.service.api.pipeline.PipelineNodeLoggerService;
import com.jcraft.jsch.ChannelShell;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.io.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;


/**
 * 节点抽象执行类
 * @author cww
 * @date 2022/6/20
 */
@Slf4j
public abstract class AbstractExecutableNode implements ExecutableNode {

    @Resource
    private PipelineExecuteLoggerSocketService loggerService;
    @Resource
    private PipelineNodeLoggerService pipelineNodeLoggerService;

    public int shell(NodeLogger nodeLogger, PipelineExecuteContext executeContext, MachineInfoDO machineInfoDO, String... commands) {
        int statusCode = -1;
        long loggerUuid =nodeLogger.getLoggerUuid();
        String nodeUuid = nodeLogger.getNodeUuid();
        nodeLogger.setLoggerUuid(loggerUuid);
        //loggerUuid得转换成String类型，才能生成key，然后才能通过websocket实时推送节点执行日志
        String key = String.format("%s&%s", Long.valueOf(loggerUuid).toString(), nodeUuid);
//        ChannelShell channel=null;
//        InputStream in = null;
//        OutputStream os = null;
//        //该code表明命令的执行是否成功，只有返回0才成功
//        try {
//            try{
//                channel = channelManager.getChannelShell(machineInfoDO);
//                in = channel.getInputStream();
//                channel.setPty(true);
//                channel.connect();
//                os = channel.getOutputStream();
//            }catch (Exception e){
//                String errormessage="与机器建立连接失败"+"\r\n";
//                ErrorHandle(e,nodeLogger,errormessage);
//                loggerService.sendMessage(key,errormessage+e.getMessage());
//            }
//            //拼接命令
//            StringBuilder cmdsb = new StringBuilder();
//            for (String cmd : commands) {
//                cmdsb.append(cmd).append(CommandConst.ENTER);
//            }
//
//            cmdsb.append(CommandConst.EXIT);
//
//            byte[] commandBytes = cmdsb.toString().getBytes();
//            os.write(commandBytes);
//            os.flush();
//
////          long startTime = System.currentTimeMillis();
//            byte[] buffer = new byte[1024];
//            while (true) {
//                while (in.available() > 0) {
//                    int i = in.read(buffer, 0, 1024);
//                    if (i < 0) {
//                        break;
//                    }
//                    //将机器返回的执行信息构建成String类型，
//                    String resp = new String(buffer, 0, i);
//                    if (resp.indexOf(NodeConst.MORE) >= 0) {
//                        os.write((NodeConst.BLANK).getBytes());
//                        os.flush();
//                    }
//                    log.debug(resp);
////                    startTime = System.currentTimeMillis();
//                    log.info("推送日志数据 key:{}", key);
//                    //拼接机器返回的信息
//                    nodeLogger.append(resp);
//                    System.out.println("========================================resp=============================");
//                    System.out.println(resp);
//                    System.out.println("========================================resp==============================");
//                    //通过WebSocket实时返回该节点的执行日志信息
//                    loggerService.sendMessage(key, resp);
//                }
//                if (channel.isClosed()) {
//                    if (in.available() > 0) {
//                        continue;
//                    }
//                    returnCode=channel.getExitStatus();
//                    log.info("exit-status: " + channel.getExitStatus());
//                    break;
//                }
//                //十秒钟未响应退出
////                if (System.currentTimeMillis() - startTime > 10000) {
////                    loggerService.sendMessage(key, String.format("%s%s%s", CommandConst.ENTER,"响应超时", CommandConst.ENTER));
////                    break;
////                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                os.close();
//                in.close();
//                if(returnCode==0){
//                    nodeLogger.setFinalStatus("成功");
//                }else{
//                    nodeLogger.setFinalStatus("失败");
//                }
//                nodeLogger.serializable();//序列化
//                nodeLogger.setExecuteEndTime(new Date());
//                //更新节点执行记录
//                pipelineNodeLoggerService.updateByNodeLogger(nodeLogger);
//                //主动释放当前socket连接
//                loggerService.close(key);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
        //建立SSH连接
        try {
            SshClient ssh = SshClientFactory.createSsh(machineInfoDO);
            List<String> commandList= Arrays.asList(commands);
            //执行命令，并且把命令的执行回传到前端
            statusCode=ssh.exec(commandList,var->{
                loggerService.sendMessage(key, var);
                nodeLogger.append(var);
            });
            log.info("exit-status: " + statusCode);
            if(statusCode==0){
                nodeLogger.setFinalStatus("成功");
            }else{
                nodeLogger.setFinalStatus("失败");
            }
            nodeLogger.serializable();//序列化
            nodeLogger.setExecuteEndTime(new Date());
            //更新节点执行记录
            pipelineNodeLoggerService.updateByNodeLogger(nodeLogger);
            //主动释放当前socket连接
            loggerService.close(key);
        }catch (Exception e){
            String errorMessage="与机器建立SSH连接出错"+CommandConst.ENTER;
            ErrorHandle(e,nodeLogger,errorMessage);
        }
        return statusCode;
    }

     public void ErrorHandle(Exception e,NodeLogger nodeLogger,String errorMessage) {
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
         e.printStackTrace(pw);
         //保存出错信息
         nodeLogger.append(errorMessage+sw.toString());
         nodeLogger.serializable();//序列化
         nodeLogger.setExecuteEndTime(new Date());
         pipelineNodeLoggerService.updateByNodeLogger(nodeLogger);
         try {
             sw.close();
             pw.close();
         }catch (IOException e2){
             e2.printStackTrace();
         }

     }

}
